// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: fengyang
#pragma once

#include <iostream>
#include <memory>
#include <optional>
#include <regex>
#include <set>
#include <sstream>
#include <string>
#include <vector>

#include <boost/date_time/posix_time/posix_time.hpp>

#include "coin2/exchange/base/symbology/derivative_util.h"
#include "coin2/exchange/base/symbology/spot_product.h"
#include "coin2/exchange/bitget/symbology/currency.h"

namespace coin2::exchange::bitget::symbology {
using ExchangeType = base::market::ExchangeType;
using coin2::exchange::bitget::symbology::BitgetCurrency;

class BitgetProduct : public base::symbology::SpotProduct<BitgetCurrency, BitgetProduct>,
                      public base::symbology::ProductFromStrMixin<BitgetProduct> {
 public:
  typedef SpotProduct<BitgetCurrency, BitgetProduct> BaseProduct;
  using ContractType = base::symbology::ContractType;

 public:
  typedef struct {
    bool success;
    std::unique_ptr<BitgetCurrency> base;
    std::unique_ptr<BitgetCurrency> quote;
  } result_t;

  BitgetProduct(const BitgetCurrency& base, const BitgetCurrency& quote)
      : SpotProduct(
            base,
            quote,
            ToBitgetOrderNativeProduct(base, quote),
            ToBitgetFeedNativeProduct(base, quote),
            base::market::ExchangeType::Bitget) {}

 public:
  static std::unique_ptr<BitgetProduct> FromNativeStrImpl(
      const std::string& native_product,
      int64_t resolve_timestamp) {
    auto [success, base, quote] = ParseBitgetNativeProduct(native_product, resolve_timestamp);
    if (success) {
      return std::make_unique<BitgetProduct>(*base, *quote);
    } else {
      return {};
    }
  }

  static result_t ParseBitgetNativeProduct(
      const std::string& product_str,
      int64_t resolve_timestamp) {
    result_t result;

    std::vector<std::string> splitted = Split(product_str, "_");
    static const std::regex reg("([A-Z0-9]{1,15})(BTC|USDC|USDT|ETH|BRL|EUR|GBP|RUB|UAH)");
    std::smatch match;
    bool res = std::regex_match(splitted[0], match, reg);
    if (!res) {
      result.success = false;
      return result;
    }

    std::string native_base = match[1];
    std::string native_quote = match[2];

    result.success = true;
    result.base = BitgetCurrency::FromNativeStrNoThrow(native_base, resolve_timestamp);
    result.quote = BitgetCurrency::FromNativeStrNoThrow(native_quote, resolve_timestamp);

    return result;
  }

  static std::string ToBitgetOrderNativeProduct(
      const BitgetCurrency& base,
      const BitgetCurrency& quote) {
    using base::market::MarketType;
    return base.native_currency(MarketType::Spot) + quote.native_currency(MarketType::Spot) +
           std::string("_SPBL");
  }

  static std::string ToBitgetFeedNativeProduct(
      const BitgetCurrency& base,
      const BitgetCurrency& quote) {
    using base::market::MarketType;
    return base.native_currency(MarketType::Spot) + quote.native_currency(MarketType::Spot);
  }
};

}  // namespace coin2::exchange::bitget::symbology
